package com.hundsun.epay.autosimu.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.hundsun.epay.autosimu.config.Channel;
import com.hundsun.epay.autosimu.config.PayCorporation;
import com.hundsun.epay.autosimu.internal.rules.FieldControlRefRules;
import com.hundsun.epay.autosimu.internal.rules.Rules;
import com.hundsun.epay.autosimu.utils.StringUtility;

public abstract class IntrospectedChannel {
	protected enum InternalAttributes{
		ATTR_CONTROLLER_IMPL_TYPE,     //包名+类名
		ATTR_CONTROLLER_CLASSNAME,    //类名
	}
	protected Map<IntrospectedChannel.InternalAttributes, Object> internalAttributes;
	protected Channel channelConfig;
	protected PayCorporation payCorpConfig;
	protected List<IntrospectedTrade> trades;
	protected Map<String, IntrospectedFieldControl> fieldControlMap;
	
	public IntrospectedChannel() {
		trades = new ArrayList<IntrospectedTrade>();
		internalAttributes = new HashMap<IntrospectedChannel.InternalAttributes, Object>();
		fieldControlMap = new HashMap<String, IntrospectedFieldControl>();
	}
	
	public void addIntrospectedFieldControl(IntrospectedFieldControl fieldControl){
		if(fieldControl != null){
			String id = fieldControl.tradeConfig.getId() + "." + fieldControl.fieldConfig.getId();
			fieldControlMap.put(id, fieldControl);
		}
	}
	
	public IntrospectedFieldControl getIntrospectedFieldControl(String id){
		IntrospectedFieldControl actual = fieldControlMap.get(id);
		if(actual == null) {
			throw new RuntimeException("Appointed field id invalid");
		}
		return actual;
	}
	
	public List<IntrospectedFieldControl> getActualIntrospectedFieldControl(String id){
		IntrospectedFieldControl actual = getIntrospectedFieldControl(id);
		List<IntrospectedFieldControl> controls = new ArrayList<IntrospectedFieldControl>();
		if(actual.getFieldControlIsRef()) {
			for (Rules rule : actual.getFieldControlRef()) {
				FieldControlRefRules refRule = (FieldControlRefRules) rule;
				controls.addAll(getActualIntrospectedFieldControl(refRule.getAbsoluteFieldId()));
			}
		}else {
			controls.add(actual);
		}
		return controls;
	}
	
	/**
	 * @return the fieldControlMap
	 */
	public Map<String, IntrospectedFieldControl> getFieldControlMap() {
		return fieldControlMap;
	}

	public void addIntrospectedTrade(IntrospectedTrade trade){
		if(trade != null){
			trades.add(trade);
		}
	}

	public Channel getChannelConfig() {
		return channelConfig;
	}

	public void setChannelConfig(Channel channelConfig) {
		this.channelConfig = channelConfig;
	}

	public PayCorporation getPayCorpConfig() {
		return payCorpConfig;
	}

	public void setPayCorpConfig(PayCorporation payCorpConfig) {
		this.payCorpConfig = payCorpConfig;
	}
	
	public void initialize(){
		//初始化controller类信息
		calculateControllerAttribute();
		
		//初始化交易
		for (IntrospectedTrade introTrade : trades) {
			introTrade.initialize();
		}
		
		for (Entry<String, IntrospectedFieldControl> entry : fieldControlMap.entrySet()) {
			entry.getValue().initialize();
		}
	}
	
	//计算controller类名
	protected void calculateControllerAttribute(){
		StringBuilder sb = new StringBuilder();
		sb.append(calculateChannelControllerName());
		setControllerClassName(sb.toString());
		
		sb.setLength(0);
		sb.append("com.hundsun.epay.simu");
		sb.append(".");
		sb.append(calculatePayCorpPackage());
		sb.append(".");
		sb.append(internalAttributes.get(InternalAttributes.ATTR_CONTROLLER_CLASSNAME));
		setControllerImplType(sb.toString());
	}
	
	protected String calculatePayCorpPackage(){
		if(StringUtility.isBlank(payCorpConfig.getPackageName())){
			return StringUtility.trimUntilFirstLetter(StringUtility.trimAllNonWrod(payCorpConfig.getId())).toLowerCase();
		}
		return payCorpConfig.getPackageName();
	}
	
	protected String calculateChannelControllerName(){
		if(StringUtility.isBlank(channelConfig.getClassName())){
			return StringUtility.convertFristLetterCase(StringUtility.trimUntilFirstLetter(StringUtility.lineToCamel(channelConfig.getId())), true);
		}else{
			return channelConfig.getClassName();
		}
	}
	
	public void setControllerImplType(String type){
		internalAttributes.put(InternalAttributes.ATTR_CONTROLLER_IMPL_TYPE, type);
	}
	
	public void setControllerClassName(String type){
		internalAttributes.put(InternalAttributes.ATTR_CONTROLLER_CLASSNAME, type);
	}
	
	public String getControllerImplType(){
		return (String) internalAttributes.get(InternalAttributes.ATTR_CONTROLLER_IMPL_TYPE);
	}
	
	public String getControllerClassName(){
		return (String) internalAttributes.get(InternalAttributes.ATTR_CONTROLLER_CLASSNAME);
	}
	
	public List<IntrospectedTrade> getTrades() {
		return trades;
	}

	public abstract List<GeneratedJavaFile> getGenerateJavaFiles();
	
	public abstract void initGenerators(List<String> wrannings);
}
